

#include "UFLBaseType.h"
#include "UFLToolKit.h"
#include "UFLMesh.h"

#include <vector>
#include <assert.h>

using std::vector;
using namespace ufl;

namespace
{
	const int Triangle_Vertex_Count = 3;
	const int Vertex_Stride = 4;
	const int Normal_Stride = 3;
	const int UV_Stride = 2;

	inline glm::vec4 convertToVex4F(const FbxVector4& v)
	{
		glm::vec4 output;
		output.x = static_cast<float>(v[0]);
		output.y = static_cast<float>(v[1]);
		output.z = static_cast<float>(v[2]);
		output.w = 1.0f;
		return output;
	}
	inline glm::vec3 convertToVex3F(const FbxVector4& v)
	{
		glm::vec3 output;
		output.x = static_cast<float>(v[0]);
		output.y = static_cast<float>(v[1]);
		output.z = static_cast<float>(v[2]);
		return output;
	}
	inline glm::vec2 convertToVex2F(const FbxVector2& v)
	{
		glm::vec2 output;
		output.x = static_cast<float>(v[0]);
		output.y = static_cast<float>(v[1]);
		return output;
	}
}

//---------------------//
//--  UFL Base Mesh  --//
//---------------------//

UFLMesh::UFLMesh()
:_hasUV(false), _hasNormal(false), _vao_id(0)
{
	memset(_vbo_ids, 0, 2);
}

UFLMesh::~UFLMesh()
{
	glDeleteVertexArrays(1, &_vao_id);
	glDeleteBuffers(VBO_COUNT, _vbo_ids);
}

void UFLMesh::beginDraw()
{
	glBindVertexArray(_vao_id);

	// º∆À„∂•µ„ Ù–‘∆´“∆¡ø
	V4F_T2F_N3F tmp;
	memset(&tmp, 0, sizeof(tmp));
	ufl_int32 perVertexSize = sizeof(tmp);
	ufl_int32 positionSize = sizeof(tmp.v);
	ufl_int32 texCoordSize = sizeof(tmp.t);

	glBindBuffer(GL_ARRAY_BUFFER, _vbo_ids[VERTEX_VBO]);
	glVertexAttribPointer(0, Vertex_Stride, GL_FLOAT, GL_FALSE, perVertexSize, reinterpret_cast<GLvoid*>(0));
	glEnableVertexAttribArray(0);

	// Œ∆¿Ì◊¯±Í
	if (_hasUV)
	{
		glVertexAttribPointer(1, UV_Stride, GL_FLOAT, GL_FALSE, perVertexSize, reinterpret_cast<GLvoid*>(positionSize));
		glEnableVertexAttribArray(1);
	}

	// ∑®œﬂ
	if (_hasNormal)
	{
		glVertexAttribPointer(2, Normal_Stride, GL_FLOAT, GL_FALSE, perVertexSize, reinterpret_cast<GLvoid*>(positionSize + texCoordSize));
		glEnableVertexAttribArray(2);
	}

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo_ids[INDEX_VBO]);
}

void UFLMesh::endDraw()
{
	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glDisableVertexAttribArray(0);
	if (_hasUV)
		glDisableVertexAttribArray(1);

	if (_hasNormal)
		glDisableVertexAttribArray(2);
}

//---------------------//
//--  UFL FBX Mesh   --//
//---------------------//
UFLFbxMesh::UFLFbxMesh()
:UFLMesh()
{

}

UFLFbxMesh::~UFLFbxMesh()
{

}

bool UFLFbxMesh::import(const char* filename)
{
	// initialize FBX I/O
	FbxManager* fbxMgr = FbxManager::Create();
	FbxIOSettings* ios = FbxIOSettings::Create(fbxMgr, IOSROOT);
	fbxMgr->SetIOSettings(ios);

	// initialize FBX importer
	FbxImporter* fbxImporter = FbxImporter::Create(fbxMgr, "");
	if (!fbxImporter->Initialize(filename, -1, fbxMgr->GetIOSettings()))
	{
		fprintf(stderr, "Call to FbxImporter::Initialize() failed.\n");
		fprintf(stderr, "Error returned: %s\n\n", fbxImporter->GetStatus().GetErrorString());
		return false;
	}

	// import data
	FbxScene* scene = FbxScene::Create(fbxMgr, "MyScene");
	fbxImporter->Import(scene);
	fbxImporter->Destroy();

	// parse node
	FbxNode* root = scene->GetRootNode();
	if (root)
	{
		for (int i = 0; i < root->GetChildCount(); i++)
		{
			parseNode(root->GetChild(i));
		}
	}

	return true;
}

void UFLFbxMesh::parseNode(FbxNode* node)
{
	if (node && node->GetNodeAttribute())
	{
		switch (node->GetNodeAttribute()->GetAttributeType())
		{
		case FbxNodeAttribute::EType::eMesh:
			parseMesh(node);
			break;

		default:
			break;
		}
	}
}

void UFLFbxMesh::parseMesh(FbxNode* node)
{
	FbxMesh* mesh = node->GetMesh();
	if (!mesh)
	{
		fprintf(stderr, "Node: %s isn't a mesh.", node->GetName());
		return;
	}

	const int polygonCount = mesh->GetPolygonCount();
	bool allByControlPoint = true;

	// ±È¿˙Õ¯∏Ò «∑Ò¥Ê”–≤ƒ÷ –≈œ¢
	FbxLayerElementArrayTemplate<int>* materialIndice = NULL;
	FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone;

	if (mesh->GetElementMaterial())
	{
		materialIndice = &mesh->GetElementMaterial()->GetIndexArray();
		lMaterialMappingMode = mesh->GetElementMaterial()->GetMappingMode();
		if (materialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon)
		{

			FBX_ASSERT(materialIndice->GetCount() == polygonCount);
			if (materialIndice->GetCount() == polygonCount)
			{
				for (int lPolygonIndex = 0; lPolygonIndex < polygonCount; ++lPolygonIndex)
				{
					const int materialIndex = materialIndice->GetAt(lPolygonIndex);
					if (_subMeshes.GetCount() < materialIndex + 1)
					{
						_subMeshes.Resize(materialIndex + 1);
					}
					if (_subMeshes[materialIndex] == NULL)
					{
						_subMeshes[materialIndex] = new SubMesh;
					}
					_subMeshes[materialIndex]->TriangleCount += 1;
				}

				for (int i = 0; i < _subMeshes.GetCount(); i++)
				{
					if (_subMeshes[i] == NULL)
						_subMeshes[i] = new SubMesh;
				}

				const int lMaterialCount = _subMeshes.GetCount();
				int lOffset = 0;
				for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex)
				{
					_subMeshes[lIndex]->IndexOffset = lOffset;
					lOffset += _subMeshes[lIndex]->TriangleCount * 3;
					_subMeshes[lIndex]->TriangleCount = 0;
				}
				FBX_ASSERT(lOffset == polygonCount * 3);
			}
		}
	}

	// À˘”–∂‡±ﬂ–Œ∂º π”√“ª∏ˆ≤ƒ÷ 
	if (_subMeshes.GetCount() == 0)
	{
		_subMeshes.Resize(1);
		_subMeshes[0] = new SubMesh();
	}

	_hasNormal = mesh->GetElementNormalCount() > 0;
	FbxGeometryElement::EMappingMode normalMappingMode = FbxGeometryElement::eNone;
	if (_hasNormal)
	{
		normalMappingMode = mesh->GetElementNormal(0)->GetMappingMode();
		if (normalMappingMode == FbxGeometryElement::eNone)
		{
			_hasNormal = false;
		}
		
		if (_hasNormal && normalMappingMode != FbxGeometryElement::eByControlPoint)
		{
			allByControlPoint = true;
		}
	}
	
	_hasUV = mesh->GetElementUVCount() > 0;
	FbxGeometryElement::EMappingMode uvMappintMode = FbxGeometryElement::eNone;
	if (_hasUV)
	{
		uvMappintMode = mesh->GetElementUV(0)->GetMappingMode();
		if (uvMappintMode == FbxGeometryElement::eNone)
		{
			_hasUV = false;
		}

		if (_hasUV && uvMappintMode != FbxGeometryElement::eByControlPoint)
		{
			allByControlPoint = false;
		}
	}

	//  Allocate the array memory.
	int polygonVertexCount = mesh->GetControlPointsCount();
	if (!allByControlPoint)
	{
		polygonVertexCount = polygonCount * Triangle_Vertex_Count;
	}

	// Use for save vertex and index.
	vector<V4F_T2F_N3F> vertices;
	vector<ufl_uint32> indices(polygonCount * Triangle_Vertex_Count, 0);
	
	// Use for save normal.
	float* normals = nullptr;
	if (_hasNormal)
		normals = new float[polygonVertexCount * Normal_Stride];

	// Use for save uv.
	float* uvs = nullptr;
	const char* uvName = NULL;
	FbxStringList uvNames;
	mesh->GetUVSetNames(uvNames);
	if (_hasUV && uvNames.GetCount())
	{
		uvs = new float[polygonVertexCount * UV_Stride];
		uvName = uvNames[0];
	}

	const FbxVector4* controlPoints = mesh->GetControlPoints();
	FbxVector4 currentVertex;
	FbxVector4 currentNormal;
	FbxVector2 currentUV;
	if (allByControlPoint) // ByControlPoint Mode
	{
		const FbxGeometryElementNormal* normalElement = nullptr;
		if (_hasNormal)
		{
			normalElement = mesh->GetElementNormal(0);
		}

		const FbxGeometryElementUV* uvElement = nullptr;
		if (_hasUV)
		{
			uvElement = mesh->GetElementUV(0);
		}

		// ∂¡»°≤¢¥Ê¥¢ Ù–‘ ˝æ›
		for (int idx = 0; idx < polygonVertexCount; ++idx)
		{
			// position, normal and texture coordination
			V4F_T2F_N3F vertex;
			memset(&vertex, 0, sizeof(vertex));

			// Save the vertex position.
			currentVertex = controlPoints[idx];
			vertex.v = convertToVex4F(currentVertex);

			// Save the normal
			if (_hasNormal)
			{
				int normalIdx = idx;
				if (normalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
				{
					normalIdx = normalElement->GetIndexArray().GetAt(idx);
				}

				currentNormal = normalElement->GetDirectArray().GetAt(normalIdx);
				vertex.n = convertToVex3F(currentNormal);
			}

			// Save the UV
			if (_hasUV)
			{
				int uvIdx = idx;
				if (uvElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
				{
					uvIdx = uvElement->GetIndexArray().GetAt(idx);
				}

				currentUV = uvElement->GetDirectArray().GetAt(uvIdx);
				vertex.t = convertToVex2F(currentUV);
			}

			vertices.push_back(vertex);
		}
	}// end, by control point

	
	int vertexCounter = 0;
	for (int polyIdx = 0; polyIdx < polygonCount; ++polyIdx)
	{
		int materialIndex = 0;
		if (materialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon)
		{
			materialIndex = materialIndice->GetAt(polyIdx);
		}

		// ¥Ê¥¢∂•µ„À˜“˝£¨»Ù∑«ByControlPointƒ£ Ω–Ë“™∂¡»°≤¢¥Ê¥¢ Ù–‘ ˝æ›
		const int lIndexOffset = _subMeshes[materialIndex]->IndexOffset + _subMeshes[materialIndex]->TriangleCount * 3;
		for (int vertexIdx = 0; vertexIdx < Triangle_Vertex_Count; ++vertexIdx)
		{
			const int controlPointIdx = mesh->GetPolygonVertex(polyIdx, vertexIdx);
			if (allByControlPoint)
			{
				indices[lIndexOffset + vertexIdx] = static_cast<unsigned int>(controlPointIdx);
			}
			else
			{
				indices[lIndexOffset + vertexIdx] = static_cast<unsigned int>(vertexCounter);

				V4F_T2F_N3F vertex;
				memset(&vertex, 0, sizeof(vertex));

				// Save the vertex position.
				currentVertex = controlPoints[controlPointIdx];
				vertex.v = convertToVex4F(currentVertex);

				// Save the normal
				if (_hasNormal)
				{
					mesh->GetPolygonVertexNormal(polyIdx, vertexIdx, currentNormal);
					vertex.n = convertToVex3F(currentNormal);
				}

				// Save the UV
				if (_hasUV)
				{
					bool unmappingUV;
					mesh->GetPolygonVertexUV(polyIdx, vertexIdx, uvName, currentUV, unmappingUV);
					vertex.t = convertToVex2F(currentUV);
				}
				
				vertices.push_back(vertex);
			}
			++vertexCounter;
		}
		_subMeshes[materialIndex]->TriangleCount += 1;
	} // end, save vertex index

	// ¥¥Ω®VAO
	glGenVertexArrays(1, &_vao_id);
	glBindVertexArray(_vao_id);

	// ¥¥Ω®VBOs
	glGenBuffers(VBO_COUNT, _vbo_ids);

	// ±£¥Ê∂•µ„ Ù–‘µΩGPU
	glBindBuffer(GL_ARRAY_BUFFER, _vbo_ids[VERTEX_VBO]);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]), &vertices[0], GL_STATIC_DRAW);

	// ±£¥Ê∂•µ„À˜“˝µΩGPU
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo_ids[INDEX_VBO]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, polygonCount * Triangle_Vertex_Count * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
}

void UFLFbxMesh::draw()
{
	beginDraw();
	ufl_uint32 subMeshCount = _subMeshes.GetCount();
	for (ufl_uint32 i = 0; i < subMeshCount; ++i)
	{
		const ufl_uint32 lOffset = _subMeshes[i]->IndexOffset * sizeof(ufl_uint32);
		const ufl_uint32 lElementCount = _subMeshes[i]->TriangleCount * 3;
		glDrawElements(GL_TRIANGLES, lElementCount, GL_UNSIGNED_INT, reinterpret_cast<GLvoid *>(lOffset));
	}
	endDraw();
}

//---------------------//
//-- UFL Sphere Mesh --//
//---------------------//
UFLSphereMesh::UFLSphereMesh()
:UFLMesh()
{
	_hasUV = true;
	_hasNormal = true;
}

UFLSphereMesh::~UFLSphereMesh()
{

}

void UFLSphereMesh::init(ufl_float radius, ufl_uint32 slices, ufl_uint32 stacks)
{
	using namespace std;

	const float PI = 3.1415926535897932384626433832795f;
	const float PI2 = 2.0f * PI;

	// …˙≥…«ÚÃÂ∂•µ„
	vector<V4F_T2F_N3F> vertices;
	for (ufl_uint32 i = 0; i <= stacks; ++i)
	{
		V4F_T2F_N3F vertex;

		// Œ∆¿Ì◊¯±ÍV
		float v = i / (float)stacks;
		float phi = v * PI;

		for (ufl_uint32 j = 0; j <= slices; ++j)
		{
			// Œ∆¿Ì◊¯±ÍU
			float u = j / (float)slices;
			float theta = u * PI2;

			// ∏˘æ›«Ú√Ê◊¯±Íœµº∆À„≥ˆ∂•µ„◊¯±Í
			float x = cos(theta) * sin(phi) * radius;
			float y = cos(phi) * radius;
			float z = sin(theta) * sin(phi) * radius;

			vertex.v = ufl_vertex_4f(x, y, z, 1.0f);
			vertex.n = ufl_vertex_3f(x, y, z);
			vertex.t = ufl_vertex_2f(u, v);
			vertices.push_back(vertex);
		}
	}

	// …˙≥…«ÚÃÂ∂•µ„À˜“˝
	vector<ufl_uint32> indicies;
	for (ufl_uint32 i = 0; i < slices * stacks + slices; ++i)
	{
		indicies.push_back(i);
		indicies.push_back(i + slices + 1);
		indicies.push_back(i + slices);

		indicies.push_back(i + slices + 1);
		indicies.push_back(i);
		indicies.push_back(i + 1);
	}

	// ¥Ê¥¢À˜“˝ ˝¡ø
	_numIndices = indicies.size();

	// ¥¥Ω®VAO
	glGenVertexArrays(1, &_vao_id);
	glBindVertexArray(_vao_id);

	// ¥¥Ω®VBO
	glGenBuffers(VBO_COUNT, _vbo_ids);

	// ±£¥Ê∂•µ„ Ù–‘µΩGPU
	glBindBuffer(GL_ARRAY_BUFFER, _vbo_ids[VERTEX_VBO]);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(V4F_T2F_N3F), &vertices[0], GL_STATIC_DRAW);

	// ±£¥Ê∂•µ„À˜“˝µΩGPU
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo_ids[INDEX_VBO]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(ufl_uint32), &indicies[0], GL_STATIC_DRAW);
}

void UFLSphereMesh::draw()
{
	beginDraw();
	glDrawElements(GL_TRIANGLES, _numIndices, GL_UNSIGNED_INT, reinterpret_cast<ufl_voidp>(0));
	endDraw();
}

//----------------------//
//--  UFL Plane Mesh  --//
//----------------------//
UFLPlaneMesh::UFLPlaneMesh()
:UFLMesh(), _numIndices(0)
{
	_hasUV = true;
	_hasNormal = true;
}

UFLPlaneMesh::~UFLPlaneMesh()
{

}

void UFLPlaneMesh::init(ufl_float xsize, ufl_float zsize, ufl_int32 xdivs, ufl_int32 zdivs, ufl_float smax /* = 1.0f */, ufl_float tmax /* = 1.0f */)
{
	
	// …˙≥…∆Ω√Ê∂•µ„
	vector<V4F_T2F_N3F> vertices;
	float x2 = xsize / 2.0f;
	float z2 = zsize / 2.0f;
	float iFactor = (float)zsize / zdivs;
	float jFactor = (float)xsize / xdivs;
	float texi = smax / zdivs;
	float texj = tmax / xdivs;
	float x, z;
	for (int i = 0; i <= zdivs; i++) {
		V4F_T2F_N3F vertex;
		z = iFactor * i - z2;
		for (int j = 0; j <= xdivs; j++) {
			x = jFactor * j - x2;
			vertex.v = ufl_vertex_4f(x, 0.0f, z, 1.0f);
			vertex.n = ufl_vertex_3f(0.0f, 1.0f, 0.0f);
			vertex.t = ufl_vertex_2f(j * texi, i * texj);
			vertices.push_back(vertex);
		}
	}
	
	// …˙≥…∆Ω√ÊÀ˜“˝
	vector<ufl_uint32> indicies;
	unsigned int rowStart, nextRowStart;
	for (int i = 0; i < zdivs; i++) {
		rowStart = i * (xdivs + 1);
		nextRowStart = (i + 1) * (xdivs + 1);
		for (int j = 0; j < xdivs; j++) {
			indicies.push_back(rowStart + j);
			indicies.push_back(nextRowStart + j);
			indicies.push_back(nextRowStart + j + 1);

			indicies.push_back(rowStart + j);
			indicies.push_back(nextRowStart + j + 1);
			indicies.push_back(rowStart + j + 1);
		}
	}

	// ¥Ê¥¢À˜“˝ ˝¡ø
	_numIndices = indicies.size();

	// ¥¥Ω®VAO
	glGenVertexArrays(1, &_vao_id);
	glBindVertexArray(_vao_id);

	// ¥¥Ω®VBO
	glGenBuffers(VBO_COUNT, _vbo_ids);

	// ±£¥Ê∂•µ„ Ù–‘µΩGPU
	glBindBuffer(GL_ARRAY_BUFFER, _vbo_ids[VERTEX_VBO]);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(V4F_T2F_N3F), &vertices[0], GL_STATIC_DRAW);

	// ±£¥Ê∂•µ„À˜“˝µΩGPU
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo_ids[INDEX_VBO]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(ufl_uint32), &indicies[0], GL_STATIC_DRAW);
}

void UFLPlaneMesh::draw()
{
	beginDraw();
	glDrawElements(GL_TRIANGLES, _numIndices, GL_UNSIGNED_INT, reinterpret_cast<ufl_voidp>(0));
	endDraw();
}

//-----------------------//
//--   UFL Cube Mesh   --//
//-----------------------//
UFLCubeMesh::UFLCubeMesh()
:UFLMesh()
{
    _hasUV = true, _hasNormal = true;
}

UFLCubeMesh::~UFLCubeMesh()
{
    
}

void UFLCubeMesh::init(ufl_float side)
{
    ufl_float side2 = side * 0.5f;
    
    // 各个面的法线
    ufl_vertex_3f frontNormal = ufl_vertex_3f(0.0f, 0.0f, 1.0f);
    ufl_vertex_3f rightNormal = ufl_vertex_3f(1.0f, 0.0f, 0.0f);
    ufl_vertex_3f backNormal = ufl_vertex_3f(0.0f, 0.0f, -1.0f);
    ufl_vertex_3f leftNormal = ufl_vertex_3f(-1.0f, 0.0f, 0.0f);
    ufl_vertex_3f bottomNormal = ufl_vertex_3f(0.0f, -1.0f, 0.0f);
    ufl_vertex_3f topNormal = ufl_vertex_3f(0.0f, 1.0f, 0.0f);
    
    // 通用纹理坐标
    ufl_vertex_2f t1(0.0f, 0.0f);
    ufl_vertex_2f t2(1.0f, 0.0f);
    ufl_vertex_2f t3(1.0f, 1.0f);
    ufl_vertex_2f t4(0.0f, 1.0f);
    
    V4F_T2F_N3F vertices[] =
    {
        // Front
        {ufl_vertex_4f(-side2, -side2, side2, 1.0f), t1, frontNormal},
        {ufl_vertex_4f( side2, -side2, side2, 1.0f), t2, frontNormal},
        {ufl_vertex_4f( side2,  side2, side2, 1.0f), t3, frontNormal},
        {ufl_vertex_4f(-side2,  side2, side2, 1.0f), t4, frontNormal},
        
        // Right
        {ufl_vertex_4f( side2, -side2, side2, 1.0f), t1, rightNormal},
        {ufl_vertex_4f( side2, -side2, -side2, 1.0f), t2, rightNormal},
        {ufl_vertex_4f( side2,  side2, -side2, 1.0f), t3, rightNormal},
        {ufl_vertex_4f( side2,  side2, side2, 1.0f), t4, rightNormal},
        
        // Back
        {ufl_vertex_4f(-side2, -side2, -side2, 1.0f), t1, backNormal},
        {ufl_vertex_4f(-side2,  side2, -side2, 1.0f), t2, backNormal},
        {ufl_vertex_4f( side2,  side2, -side2, 1.0f), t3, backNormal},
        {ufl_vertex_4f( side2, -side2, -side2, 1.0f), t4, backNormal},
        
        // Left
        {ufl_vertex_4f(-side2, -side2, side2, 1.0f), t1, leftNormal},
        {ufl_vertex_4f(-side2,  side2, side2, 1.0f), t2, leftNormal},
        {ufl_vertex_4f(-side2,  side2, -side2, 1.0f), t3, leftNormal},
        {ufl_vertex_4f(-side2, -side2, -side2, 1.0f), t4, leftNormal},
        
        // Bottom
        {ufl_vertex_4f(-side2, -side2, side2, 1.0f), t1, bottomNormal},
        {ufl_vertex_4f(-side2, -side2, -side2, 1.0f), t2, bottomNormal},
        {ufl_vertex_4f( side2, -side2, -side2, 1.0f), t3, bottomNormal},
        {ufl_vertex_4f( side2, -side2, side2, 1.0f), t4, bottomNormal},
        
        // Top
        {ufl_vertex_4f(-side2,  side2, side2, 1.0f), t1, topNormal},
        {ufl_vertex_4f( side2,  side2, side2, 1.0f), t2, topNormal},
        {ufl_vertex_4f( side2,  side2, -side2, 1.0f), t3, topNormal},
        {ufl_vertex_4f(-side2,  side2, -side2, 1.0f), t4, topNormal},
    };
    
    ufl_uint32 indices[] =
    {
        0,1,2,0,2,3,
        4,5,6,4,6,7,
        8,9,10,8,10,11,
        12,13,14,12,14,15,
        16,17,18,16,18,19,
        20,21,22,20,22,23
    };
    
    // 创建VAO并绑定
    glGenVertexArrays(1, &_vao_id);
    glBindVertexArray(_vao_id);
    
    // 创建VBOs并绑定
    glGenBuffers(VBO_COUNT, _vbo_ids);
    
    // 绑定顶点缓冲
    glBindBuffer(GL_ARRAY_BUFFER, _vbo_ids[VERTEX_VBO]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    // 绑定索引缓冲
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo_ids[INDEX_VBO]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}

void UFLCubeMesh::draw()
{
    beginDraw();
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, reinterpret_cast<ufl_voidp>(0));
    endDraw();
}










